package com.program.controller;

import com.program.eneity.Airplane;
import com.program.eneity.Date;
import com.program.eneity.FlightSchedule;
import com.program.services.AirplaneService;
import com.program.services.EventService;
import com.program.services.RunwayService;
import com.program.utils.LinkQueue;
import com.program.utils.PriorityQueue;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import java.net.URL;
import java.util.Calendar;
import java.util.ResourceBundle;
import java.util.concurrent.*;

/**
 * @program: AirportSystem
 * @description: 页面控制器
 * @author: 19071027
 * @create: 2021-09-10 18:54
 **/
public class MainController implements Initializable {

    public static MainController mainController;

    @FXML
    private Text dateText;

    @FXML
    private Text numTotalText;

    @FXML
    private Text numInText;

    @FXML
    private Text numOutText;

    @FXML
    private Text progressText;

    @FXML
    private TextArea alertsText;

    @FXML
    private Text state1;

    @FXML
    private Text state2;

    @FXML
    private Text state3;

    @FXML
    private Text state4;

    @FXML
    private Text fuel1;

    @FXML
    private Text fuel2;

    @FXML
    private Text fuel3;

    @FXML
    private Text fuel4;

    @FXML
    private Label label1;

    @FXML
    private Label label2;

    @FXML
    private Label label3;

    @FXML
    private Label label4;

    @FXML
    private ImageView ico_fuel1;

    @FXML
    private ImageView ico_fuel2;

    @FXML
    private ImageView ico_fuel3;

    @FXML
    private ImageView ico_fuel4;

    @FXML
    private ImageView emergencyTag;

    @FXML
    private TableView<FlightSchedule> schedule;

    @FXML
    private TableColumn<FlightSchedule, String> companyColumn;

    @FXML
    private TableColumn<FlightSchedule, String> idColumn;

    @FXML
    private TableColumn<FlightSchedule, String> dTimeColumn;

    @FXML
    private TableColumn<FlightSchedule, String> aTimeColumn;

    @FXML
    private ImageView radar;

    @FXML
    private ImageView off1;

    @FXML
    private ImageView off2;

    @FXML
    private ImageView off3;

    @FXML
    private ImageView land1;

    @FXML
    private ImageView land2;

    @FXML
    private ImageView land3;

    @FXML
    private ImageView land4;

    @FXML
    private ImageView off4;

    @FXML
    private ListView<String> takeOffWaitingView;

    @FXML
    private ListView<String> landWaitingView;

    static AirplaneService airplaneService = AirplaneService.getAirplaneService();

    static RunwayService runwayService = RunwayService.getRunwayService();

    static EventService eventService = new EventService();

    public static PriorityQueue landPriorityQueue = new PriorityQueue();

    public static PriorityQueue offPriorityQueue = new PriorityQueue();

    public static LinkQueue<Airplane> takeOffAirplanes = airplaneService.getTakeOffAirplanes();

    public static LinkQueue<Airplane> landAirplanes = airplaneService.getLandAirplanes();

    public static PriorityQueue takeOffWaiting = new PriorityQueue();

    public static PriorityQueue landingWaiting = new PriorityQueue();

    public static ObservableList<String> offList = FXCollections.observableArrayList();

    public static ObservableList<String> landList = FXCollections.observableArrayList();

    /**
     * 实时时间
     */
    public static Date date = new Date();

    /**
     * 程序执行毫秒数
     */
    private int millisecond = 0;

    /**
     * 飞机图像y坐标
     */
    double y = 0;

    /**
     * 飞机燃油状态图标
     */
    private Image imageFuel;

    /**
     * 航班延误时间
     */
    private int delayMin = 0;


    public void mainController() {
        //初始化部分图像
        initView();

        //获取需要调度的飞机
        airplaneService.createAirplanes();

        loadSchedule(airplaneService.getFlightSchedules());

        //初始化开始时间
        date = airplaneService.getStartDate();

        //将飞机分成起飞和降落两组
        airplaneService.classifyAirplanes();

        //加载等待队列UI
        loadWaitingListUI();

        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3);

        //定时任务
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                millisecond += 100;

                if (millisecond % eventService.getRealTime() == 0) {
                    //改变时间
                    eventService.changeDate(date);
                    updateDateText();

                    //减少飞机燃油
                    eventService.reduceFuel();

                    //释放跑道资源
                    runwayService.release(date);
                    releaseRunwayUI();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //等待队列
                    airplaneService.createWaitingQueue();

                    //优先级队列
                    airplaneService.createPriorityQueue();

                    //分配跑道
                    while (!MainController.landPriorityQueue.isEmpty() || !MainController.offPriorityQueue.isEmpty()) {
                        String infoLand = runwayService.allocateLand(date);
                        String infoOff = runwayService.allocateOff(date);
                        if ("FULL".equals(infoLand)||"FULL".equals(infoOff)){
                            //跑道已满
                            break;
                        }else if (infoLand!=null||infoOff!=null){
                            if (infoLand!=null){
                                showAlertsInfo(infoLand);
                            }else{
                                showAlertsInfo(infoOff);
                            }
                        }
                    }


                }

                showNumInfo();

                showRadar();

                loadRunwayInfoUI();

            }
        };

        //100毫秒刷新一次画面
        scheduledThreadPoolExecutor.scheduleAtFixedRate(runnable, 0, 100, TimeUnit.MILLISECONDS);

    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        mainController = this;
    }

    /**
     * 更新页面的当前时间文本
     */
    public void updateDateText() {
        Platform.runLater(() -> {
            String timeStr = date.toString();
            dateText.setText(timeStr);
        });
    }

    /**
     * 加载航班表表格
     *
     * @param flightSchedules 航班表数据
     */
    public void loadSchedule(FlightSchedule[] flightSchedules) {
        ObservableList<FlightSchedule> data = FXCollections.observableArrayList();

        for (FlightSchedule flightSchedule : flightSchedules) {
            data.add(flightSchedule);
        }

        companyColumn.setCellValueFactory(flightScheduleStringCellDataFeatures -> flightScheduleStringCellDataFeatures.getValue().companyProperty());
        idColumn.setCellValueFactory(flightScheduleStringCellDataFeatures -> flightScheduleStringCellDataFeatures.getValue().idProperty());
        dTimeColumn.setCellValueFactory(flightScheduleStringCellDataFeatures -> flightScheduleStringCellDataFeatures.getValue().dTimeProperty());
        aTimeColumn.setCellValueFactory(flightScheduleStringCellDataFeatures -> flightScheduleStringCellDataFeatures.getValue().aTimeProperty());

        schedule.setItems(data);

    }

    /**
     * 加载等待起飞队列页面
     */
    private void loadWaitingListUI() {
        takeOffWaitingView.setItems(offList);
        landWaitingView.setItems(landList);
    }

    /**
     * 加载跑道信息页面
     */
    private void loadRunwayInfoUI() {
        Platform.runLater(() -> {
            if (RunwayService.getRunway1().getAirplane() != null) {
                label1.setText(RunwayService.getRunway1().getAirplane().getId());
                if (RunwayService.getRunway1().getAirplane().getLandingTime() == null) {
                    state1.setText("起飞");
                    off1.setVisible(true);
                    Image image = new Image("img/ico_fuel1.png");
                    ico_fuel1.setImage(image);
                    ico_fuel1.setVisible(true);
                    setPosition(off1, "off");
                }
                else {
                    state1.setText("着陆");
                    land1.setVisible(true);
                    selectImageFuel(RunwayService.getRunway1().getAirplane().getFuel());
                    ico_fuel1.setImage(imageFuel);
                    ico_fuel1.setVisible(true);
                    setPosition(land1, "land");
                }
                fuel1.setText(String.valueOf(RunwayService.getRunway1().getAirplane().getFuel()));

            }

            if (RunwayService.getRunway2().getAirplane() != null) {
                label2.setText(RunwayService.getRunway2().getAirplane().getId());
                if (RunwayService.getRunway2().getAirplane().getLandingTime() == null) {
                    state2.setText("起飞");
                    off2.setVisible(true);
                    Image image = new Image("img/ico_fuel1.png");
                    ico_fuel2.setImage(image);
                    ico_fuel2.setVisible(true);
                    setPosition(off2, "off");
                }
                else {
                    state2.setText("着陆");
                    land2.setVisible(true);
                    selectImageFuel(RunwayService.getRunway2().getAirplane().getFuel());
                    ico_fuel2.setImage(imageFuel);
                    ico_fuel2.setVisible(true);
                    setPosition(land2, "land");
                }
                fuel2.setText(String.valueOf(RunwayService.getRunway2().getAirplane().getFuel()));
            }


            if (RunwayService.getRunway3().getAirplane() != null) {
                label3.setText(RunwayService.getRunway3().getAirplane().getId());
                if (RunwayService.getRunway3().getAirplane().getLandingTime() == null) {
                    state3.setText("起飞");
                    off3.setVisible(true);
                    Image image = new Image("img/ico_fuel1.png");
                    ico_fuel3.setImage(image);
                    ico_fuel3.setVisible(true);
                    setPosition(off3, "off");
                }
                else {
                    state3.setText("着陆");
                    land3.setVisible(true);
                    selectImageFuel(RunwayService.getRunway3().getAirplane().getFuel());
                    ico_fuel3.setImage(imageFuel);
                    ico_fuel3.setVisible(true);
                    setPosition(land3, "land");
                }
                fuel3.setText(String.valueOf(RunwayService.getRunway3().getAirplane().getFuel()));
            }


            if (RunwayService.getRunway4().getAirplane() != null) {
                label4.setText(RunwayService.getRunway4().getAirplane().getId());
                if (RunwayService.getRunway4().isAvailable()||RunwayService.getRunway4().getAirplane().getLandingTime()==null||RunwayService.getRunway4().getAirplane().getFuel()>10) {
                    emergencyTag.setVisible(false);
                }
                else {
                    emergencyTag.setVisible(true);
                }
                if (RunwayService.getRunway4().getAirplane().getLandingTime() == null) {
                    state4.setText("起飞");
                    off4.setVisible(true);
                    Image image = new Image("img/ico_fuel1.png");
                    ico_fuel4.setImage(image);
                    ico_fuel4.setVisible(true);
                    setPosition(off4, "off");
                }
                else {
                    state4.setText("着陆");
                    land4.setVisible(true);
                    selectImageFuel(RunwayService.getRunway4().getAirplane().getFuel());
                    ico_fuel4.setImage(imageFuel);
                    ico_fuel4.setVisible(true);
                    setPosition(land4, "land");
                }

                fuel4.setText(String.valueOf(RunwayService.getRunway4().getAirplane().getFuel()));

            }

        });

    }

    /**
     * 释放跑道信息页面
     */
    private void releaseRunwayUI() {
        Platform.runLater(() -> {
            if (RunwayService.getRunway1().isAvailable()) {
                label1.setText(null);
                state1.setText("");
                fuel1.setText("");
                off1.setVisible(false);
                land1.setVisible(false);
                off1.setLayoutY(440);
                land1.setLayoutY(63);
                ico_fuel1.setVisible(false);
            }

            if (RunwayService.getRunway2().isAvailable()) {
                label2.setText("");
                state2.setText("");
                fuel2.setText("");
                off2.setVisible(false);
                land2.setVisible(false);
                off2.setLayoutY(440);
                land2.setLayoutY(63);
                ico_fuel2.setVisible(false);
            }

            if (RunwayService.getRunway3().isAvailable()) {
                label3.setText("");
                state3.setText("");
                fuel3.setText("");
                off3.setVisible(false);
                land3.setVisible(false);
                off3.setLayoutY(440);
                land3.setLayoutY(63);
                ico_fuel3.setVisible(false);
            }

            if (RunwayService.getRunway4().isAvailable()) {
                label4.setText("");
                state4.setText("");
                fuel4.setText("");
                off4.setVisible(false);
                land4.setVisible(false);
                off4.setLayoutY(440);
                land4.setLayoutY(63);
                ico_fuel4.setVisible(false);
                emergencyTag.setVisible(false);
            }

            Image imageRadar = new Image("img/ico_radar1.png");
            radar.setImage(imageRadar);

        });

    }

    /**
     * 设置飞机动画位置
     *
     * @param airplane
     * @param type
     */
    private void setPosition(ImageView airplane, String type) {
        y = airplane.getLayoutY();
        if ("off".equals(type)) {
            y -= 20;
        }
        else {
            if (y < 443) {
                y += 20;
            }
        }

        double newY = y;

        Platform.runLater(() -> airplane.setLayoutY(newY));

    }

    /**
     * 初始化图形
     */
    private void initView() {
        off1.setVisible(false);
        land1.setVisible(false);
        off2.setVisible(false);
        land2.setVisible(false);
        off3.setVisible(false);
        land3.setVisible(false);
        off4.setVisible(false);
        land4.setVisible(false);
        ico_fuel1.setVisible(false);
        ico_fuel2.setVisible(false);
        ico_fuel3.setVisible(false);
        ico_fuel4.setVisible(false);
        emergencyTag.setVisible(false);
        alertsText.setWrapText(true);
    }

    /**
     * 设置燃油图片
     *
     * @param fuel 飞机剩余燃油
     */
    private void selectImageFuel(int fuel) {
        if (fuel < 60 && fuel >= 10) {
            imageFuel = new Image("img/ico_fuel2.png");
        }
        else if (fuel < 10) {
            imageFuel = new Image("img/ico_fuel3.png");
        }
        else {
            imageFuel = new Image("img/ico_fuel1.png");
        }
    }

    /**
     * 显示雷达状态图标
     */
    private void showRadar() {
        if (!RunwayService.getRunway1().isAvailable() || !RunwayService.getRunway2().isAvailable() || !RunwayService.getRunway3().isAvailable() || !RunwayService.getRunway4().isAvailable()) {
            Image imageRadar = new Image("img/ico_radar2.png");
            radar.setImage(imageRadar);
        }
    }

    private void showNumInfo() {
        int numTotal = airplaneService.getNum();
        numTotalText.setText(String.valueOf(numTotal));

        int numIn = airplaneService.getNumIn();
        int numOut = airplaneService.getNumOut();
        int numEntered = runwayService.getNumEntered();
        int numLeft = runwayService.getNumLeft();
        int numDone = numEntered + numLeft;

        numInText.setText(numEntered + "/" + numIn);
        numOutText.setText(numLeft + "/" + numOut);
        progressText.setText(numDone+"/"+numTotal);
    }

    private void showAlertsInfo(String info){
        Platform.runLater(() -> alertsText.appendText(info));
    }

}
